Skip to content

GitLAB-CI-CD

GitLab CI-CD

image-20220505070058376

目录

[toc]

GitLabCI/CD简介

GitLabCI/CD简介

GitLabCI/CD是GitLab内置的持续集成与持续部署系统

image-20230425213724221

  • 开源: CI/CD是开源GitLab社区版和专有GitLab企业版的一部分。(极狐)
  • 易于学习: 官方具有详细的学习操作文档。
  • 无缝集成: CI/CD是GitLab的一部分,支持从计划到部署,具有出色的用户体验。 (例如:做一些基于版本控制系统的提交流水线、合并流水线,是很方便的!)
  • 可扩展: 可以根据需要添加任意数量的构建节点。
  • 更快的结果: 每个构建可以拆分为多个作业,这些作业可以在多台计算机上并行运行。
  • 针对交付进行了优化: 多个阶段,手动部署, 环境 和 变量。

tstmp_20230425213814

  • 针对交付进行了优化: 多个阶段,手动部署, 环境和变量。

jenkins里,你想要获取git分支、git提交用户的话,我们都需要先去抓收据,去采集数据,进行一个过滤,再拿到;

但在gitlab里,使用gitlab ci时,里面就有现成的环境变量,我们直接使用就好,所以这一点,还是有很大的优势的。这个文档是大家在开发流水线时必须依赖的一个文档,使用时要注意下这里的版本!

https:将concurrent=1改为concurrent=10

配置完后,默认生效的。

image-20230426123342605

image-20230426123350641

可以看到,这里是并行运行作业的了,符合预期。

2. 流水线页面

tstmp_20230427073303

  • 1 清除runner的缓存;
  • 2 进行CI文件语法校验;
  • 3 手动触发运行流水线;
  • 4 流水的步骤, 可以查看各个阶段的运行日志;

3. Pipeline编辑器

tstmp_20230427073424

Pipeline开发工具与设置

1.Pipeline开发工具

image-20230427073740603

可视化编辑器

变更.gitlab-ci.yml文件后, 可以通过Visualize对CI文件中的定义进行可视化;

tstmp_20230427075340

语法检测校验

通过Lint可以检测当前CI文件是否存在语法错误;若存在语法错误可以根据提示进行修正;

tstmp_20230427075408

作业运行日志

一条流水线包含很多个作业,每个作业的运行日志可以在Jobs界面看到。

tstmp_20230427075439

Pipeline环境变量

预定义变量信息:https:- build- test- deployjob0:tags:- gostage:.prescript:- echo "init"job1:tags:- gostage:buildscript:- echo "build"job2-1:tags:- mvnstage:testscript:- echo "test"- sleep 10job2-2:tags:- mvnstage:testscript:- echo "test"job3:tags:- gostage:deployscript:- echo "deploy"job10:tags:- gostage:.postscript:- echo "end"

代码直接写在gitlab的CI/CD的editor里:

image-20230508200801392

image-20230508200030139

image-20230508200055459

image-20230508200238359

如果两个或者多个作业,指向同一个阶段名称,则该阶段下的所有作业都并行运行;如果不能并行运行,需要检查runner的配置文件中的concurrent值, 要大于1。

image-20230508200545635

variables 环境变量

变量可以分为全局变量和局部变量;全局变量是整个流水线可以用的,局部变量是仅在作业中生效的;

  • CI代码
yaml
stages:- buildvariables:BUILD_TOOLS:value:"mvn"description:"choice build tools"#描述信息,注释不能用
RUNNER_TAG:"go"job1:tags:- "${RUNNER_TAG}"stage:buildvariables:BUILD_TOOLS:"gradle"script:- echo "${BUILD_TOOLS}"
  • 运行

image-20230508201543785

image-20230508201601217

job 作业默认配置

定义一个作业的时候,一般定义哪些关键字呢? 作业在哪个runner运行? 作业属于流水线中的哪个阶段? 这个作业要做什么?

  • CI代码
yaml
stages:- buildvariables:RUNNER_TAG:"go"before_script:- echo "pipeline before script"after_script:- echo "pipeline after script"job1:tags:- ${RUNNER_TAG}stage:buildbefore_script:- echo "before script...."script:- echo "mvn package"after_script:- echo "after script..."job2:tags:- ${RUNNER_TAG}stage:buildscript:- echo "build"

参数解析:

语法关键字作用备注
variables定义作业中的环境变量;
tags根据标签选择运行作业的构建节点;多个标签, 则匹配具有所有标签的构建节点;GitLab14.1版本后, 标签的值可以使用变量;GitLab14.3版本后, 标签数量必须小于50;
stage指定当前作业所属的阶段名称;
before_script作业在运行前执行的Shell命令行;
script作业在运行中执行的Shell命令行;每个作业至少要包含一个script;
after_script作业在运行后执行的Shell命令行;
  • 运行

image-20230509073124496

image-20230509073217401

image-20230509073245729

需要注意:如果before_script和after_script定义在pipeline里,则每个作业里都会运行这2个脚本;如果是定义在某个job里,则只会在其job里运行!

job 作业运行控制

语法关键字作用备注
allow_failure控制作业状态,是否允许作业失败,默认值为false 。启用后,如果作业运行失败,该作业将在用户界面中显示橙色警告。img管道将认为作业成功/通过,不会被阻塞。 假设所有其他作业均成功,则该作业的阶段及其管道将显示相同的橙色警告。但是,关联的提交将被标记为"通过",而不会发出警告。
when根据状态控制作业运行,当前面作业成功或者失败时运行。on_success 前面阶段成功时执行(默认值);on_failure 前面阶段失败时执行;always 总是执行;manual 手动执行;delayed 延迟执行;start_in'5'5 seconds30 minutes1 day1 weeknever 永不执行;
retry作业重新运行,遇到错误重新运行的次数。值为整数等于或大于0,但小于或等于2异常分类 (一般就是3次)
timeout作业运行超时时间;
rules根据特定的变量或文件变更来控制作业运行;ifchangesexists
needs作业依赖控制;needs:["作业名称"]
parallel生成多个作业,并行运行parallel:5值 2-50之间

parallel 并行运行

  • 代码
yaml
stages:- buildvariables:RUNNER_TAG:"go"job1:tags:- ${RUNNER_TAG}stage:buildparallel:5script:- echo "mvn package"

模拟做压测。

  • 运行

image-20230510204224755

image-20230510204317770

needs 作业关联运行

  • CI代码

needs 指定要依赖的作业名称

yaml
stages:- build- testvariables:RUNNER_TAG:"go"job1:tags:- ${RUNNER_TAG}stage:buildscript:- echo "mvn package"- sleep 10job2:tags:- ${RUNNER_TAG}stage:buildscript:- echo "build"job3:tags:- ${RUNNER_TAG}stage:testscript:- echo "mvn package"job4:tags:- ${RUNNER_TAG}stage:testneeds:["job2"]script:- echo "mvn package"
  • 运行

tstmp_20230510204814

tstmp_20230510204829

rules根据变量/文件控制

根据条件(变量)判断: IF

用法:

bash
定义变量条件;运算符:=!==~条件链接符:&&||

CI代码:

yaml
variables:DOMAIN:example.comcodescan:stage:buildtags:- buildrules:- if:'$DOMAIN =="example.com"'when:manual- when:on_successscript:- echo "codescan"- sleep 5;

运行:

image-20230510221518531

image-20230510221530477

image-20230510221543129

根据文件判断:changesexists

changes

文件变更时条件为真;

示例: 代码提交后,当Dockerfile文件发生变更则条件为真。即手动执行此作业。

img

注意:非Push相关动作,此条件永远为真。

CI代码:

yaml
citest1:tags:- buildstage:testrules:- changes:- Dockerfilewhen:manual- when:neverscript:- echo "Do a test here"- echo "For example run a test suite"

运行:

直接运行次作业时,肯定是不会运行流水线的,因此此时是没有Dockerfile文件的。

我们来创建一个Dockerfile文件,再次运行流水线,并观察现象:

image-20230510222132121

image-20230510222138402

allow_failure

允许作业在不停止管道的情况下失败;

CI代码:

yaml
stages:- testcitest1:tags:- buildstage:testallow_failure:truescript:- lsl -l- echo "Do a test here"citest2:tags:- buildstage:testscript:- ls -l- echo "Do a test here"

运行:

image-20230511213644637

image-20230511213721309

image-20230511213731113

variables

重新定义变量的值;

示例: 如果当前的分支是主干分支main, 则重新定义ENV_TYPE的值为prod

img

注意: 只影响局部作业内的变量,不会影响全局变量。

CI代码:

yaml
variables:ENV_TYPE:"dev"cddeploy:tags:- buildstage:deployrules:- if:$CI_COMMIT_REF_NAME =="main"variables:ENV_TYPE:"prod"script:- echo "Deploy env ${ENV_TYPE}"

运行:

image-20230511214046220

🍀 某一类文件写法:

image-20230511214327721

when

同when语法的运行方式;

这里的when是写在rules里面的,也可以写在外面的。

rules代码汇总:

yaml
stages:- build- testvariables:RUNNER_TAG:"go"SKIP_BUILD:"true"job1:tags:- ${RUNNER_TAG}stage:buildrules:- if:'$SKIP_BUILD =="true"'# 此时job1 不会被运行when:never- when:alwaysbefore_script:- echo "before script...."script:- echo "mvn package"after_script:- echo "after script..."job2:tags:- ${RUNNER_TAG}stage:testrules:- changes:- README.md# 提交时仅该文件存在变更时才会触发when:always- when:neverscript:- echo "test"job3:tags:- ${RUNNER_TAG}stage:testrules:- exists:- Dockerfile#只要项目中存在该文件就会运行,提交存在也算。when:manual- when:neverscript:- echo "test"job4:tags:- ${RUNNER_TAG}stage:testscript:- echo "test"

运行:

image-20230512072041799

when 状态控制和运行方式

  • 根据上游作业的状态决定
    • 当前作业是否运行?
    • 运行的方式?(手动/自动/定时)

CI代码:

yaml
stages:- build- test- deployvariables:RUNNER_TAG:"go"job1:tags:- ${RUNNER_TAG}stage:buildbefore_script:- echo "before script...."script:- echo "mvn package"after_script:- echo "after script..."job2:tags:- ${RUNNER_TAG}stage:testwhen:on_successscript:- echo "build"job3:tags:- ${RUNNER_TAG}stage:testwhen:on_failurescript:- echo "build"job4:tags:- ${RUNNER_TAG}stage:deploywhen:manualscript:- echo "build"

运行:

image-20230512072456135

when:delay

yaml
test1:tags:- ${RUNNER_TAG}stage:testscript:- echo "Do a test here"- echo "For example run a test suite"- sleep 3when:delaystart_in:'5'

image-20220506121738112

timeout作业运行超时时间

yaml
build:script:build.shtimeout:3 hours 30 minutestest:script:rspectimeout:3h 30m

retry 作业失败后重试次数

CI代码:

yaml
stages:- build- testvariables:RUNNER_TAG:"go"job1:tags:- ${RUNNER_TAG}stage:buildretry:2before_script:- echo "before script...."script:- echo "mvn package"- mvsafter_script:- echo "after script..."job2:tags:- ${RUNNER_TAG}stage:testscript:- echo "build"

运行:

image-20230512073129706

根据特定的错误匹配:

yaml
always :在发生任何故障时重试(默认)。unknown_failure :当失败原因未知时。script_failure :脚本失败时重试。api_failure :API失败重试。stuck_or_timeout_failure :作业卡住或超时时。runner_system_failure :构建节点的系统发生故障。missing_dependency_failure:依赖丢失。runner_unsupported :Runner不受支持。stale_schedule :无法执行延迟的作业。job_execution_timeout:作业运行超时。archived_failure :作业已存档且无法运行。unmet_prerequisites :作业未能完成先决条件任务。scheduler_failure :调度失败。data_integrity_failure :结构完整性问题。####max :最大重试次数 when :重试失败的错误类型stages:- build- testvariables:RUNNER_TAG:"go"job1:tags:- ${RUNNER_TAG}stage:buildretry:2# 不管任何错误,都重试2次before_script:- echo "before script...."script:- echo "mvn package"- mvs# 命令错误after_script:- echo "after script..."job2:tags:- ${RUNNER_TAG}stage:testwhen:on_failure# 为了让这个作业运行所以添加的,不然前面作业失败这个作业就不运行了。script:- echo "build"- aaa# 命令错误retry:max:2#when:api_failurewhen:script_failure# 定义脚本错误: 正常会retry两次

运行:

image-20230512073329001

allow_failure 允许作业失败

CI代码:

yaml
stages:- build- testvariables:RUNNER_TAG:"go"job1:tags:- ${RUNNER_TAG}stage:buildallow_failure:trueretry:2before_script:- echo "before script...."script:- echo "mvn package"- mvsafter_script:- echo "after script..."job2:tags:- ${RUNNER_TAG}stage:testscript:- echo "build"

运行:

image-20230512073710528

Pipeline运行控制

image-20230512073922712

1.workflow 控制流水线

控制管道是否创建和运行。根据条件(变量)判断: IF

  • if 定义变量条件;

  • variables 重新定义变量的值;

  • when

    • always
    • never
命令备注
if:'$CI_PIPELINE_SOURCE =="merge_request_event"'合并请求时运行流水线;
if:'$CI_PIPELINE_SOURCE =="push"'提交代码运行流水线;
  • 预定义变量

image-20230512074126286

https:SKIP_RUN:"true"RUNNER_TAG:"go"workflow:rules:- if:$CI_PIPELINE_SOURCE =="push"when:neverstages:- buildjob2:tags:- ${RUNNER_TAG}stage:buildscript:- echo "build"

运行:

运行后,是没看见触发流水线的。

🍀 demo

CI代码:

运行:

可以看到,这里在web触发时,依然报错了:……

image-20230512075826983

2.Git 选项跳过流水线

  • 提交信息中添加关键字 [ci skip]或者 [skip ci]
  • Git 2.10 更高版本,可以通过以下配置设置CI/CD;
bash
## 跳过gitpush-oci.skip## 传递变量gitpush-oci.variable="MAX_RETRIES=10"-oci.variable="MAX_TIME=600"

🍀 demo

这里改变下项目里readme文件内容,进行提交,commit message信息里写上[ci skip],再次观察是否会触发提交流水线(默认是提交一次就会触发一次流水线的)?

image-20230513075150576

image-20230513075216517

可以看到,这里跳过了流水线的触发。

3.trigger 触发下游管道

  • 触发项目管道
  • 触发子管道

strategy: 默认情况下,一旦创建了下游管道,trigger作业就会以success状态完成。要强制等待下游管道完成,使用 strategy:depend

触发项目管道:(不要自己触发自己,这样就进入到一个环里面了。)

yaml
triggers:stage:deploytrigger:project:devops/devops-maven-servicebranch:mainstrategy:depend## 状态同步

触发子管道:

yaml
stages:- deploytrigger-cd-pipeline:stage:deploytrigger:include:ci/stages.yml## 触发当前项目的子流水线trigger-project-pipeline:stage:deploytrigger:include:- project:"devops/devops05-app-service"## 触发其它项目的子流水线ref:"main"file:"ci/stages.yml"

tstmp_20230513081626

测试过程:

  • 创建一个项目

devops6-gitlabci-demo

image-20230513081821871

  • 在新项目里创建一个.gitllabci.yml文件:

image-20230513082056693

yaml
stages:- buildbefore_script:- echo "Before script section"- echo "For example you might run an update here or install a build dependency"- echo "Or perhaps you might print out some debugging details"after_script:- echo "After script section"- echo "For example you might do some cleanup here"build1:tags:- gostage:buildscript:- sleep 20- echo "Do your build here"
  • 先来测试下 触发项目管道

image-20230513082438122

yaml
stages:- deploytriggers:stage:deploytrigger:project:devops6/devops6-gitlabci-demobranch:mainstrategy:depend## 状态同步

提交代码并观察现象:

image-20230513082532404

image-20230513082635830

image-20230513082618952

可以看到,此时成功触发了其他项目。

  • 再来测试下 trigger触发当前项目的子流水线

在当前项目devops-demo-service里创建.ci/ci.yaml文件:

image-20230513094956436

yaml
stages:- build- testbuild01:stage:buildtags:- goscript:- echo "build"test01:stage:testtags:- goscript:- echo "test"

提交后,默认就会触发流水线的运行:

image-20230513095135054

此时,有这个需求:改了目录里面的内容,就不让他构建,该怎么写?

CI代码:

yaml
stages:- deployworkflow:rules:- changes:- .ci